package training.framework.presentation;

import java.util.ArrayList;
import java.util.List;

import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;

import training.framework.business.AbstractEntity;
import training.framework.business.AbstractEntityController;
import training.framework.business.AbstractEntitySearchOptions;

@ManagedBean
@SessionScoped
public abstract class AbstractSearchEntity <Identifier, 
									Entity extends AbstractEntity<Identifier>, 
									EntitySearchOptions extends AbstractEntitySearchOptions, 
									EntityPanel extends AbstractEntityPanel<Identifier, Entity>> {
	
	
	private Class<EntitySearchOptions> optionsClass;
	private EntitySearchOptions options;
	private List<Integer> pages;
	private int page;
	private List<Entity> result;
	private String initializeOutCome;
	private String entityNotFoundMessage;
	private int maxResults;

	
	public AbstractSearchEntity(Class<EntitySearchOptions> optionsClass, String initializeOutCome, String entityNotFoundMessage, int maxResults) {
		if(optionsClass == null){
			throw new IllegalArgumentException("optionsClass == null ");
		}
		
		if(initializeOutCome == null){
			throw new IllegalArgumentException("initializeOutCome == null ");
		}
		
		if(entityNotFoundMessage == null){
			throw new IllegalArgumentException("entityNotFoundMessage == null ");
		}
		
		this.optionsClass = optionsClass;
		this.initializeOutCome = initializeOutCome;
		this.entityNotFoundMessage = entityNotFoundMessage;
		this.maxResults = maxResults;
	}
	
	public String initialize() throws InstantiationException, IllegalAccessException {
		options = optionsClass.newInstance();
		options.setMaxResults(this.maxResults);
		pages = null;
		result = null;
		return initializeOutCome;
	}

	public EntitySearchOptions getOptions() {
		return options;
	}

	public List<Integer> getPages() {
		return pages;
	}
	
	public int getPage() {
		return page;
	}		
	
	public List<Entity> getResult() {
		return result;
	}

	public void searchEntity() {
		pages = new ArrayList<Integer>();
		AbstractEntityController<Identifier, Entity, EntitySearchOptions> controller = getController();
		
		int postCount = controller.searchEntityCount(options);
		if (postCount == 0) {
			FacesMessage message = new FacesMessage();
			message.setSeverity(FacesMessage.SEVERITY_INFO);
			message.setSummary(entityNotFoundMessage);
			FacesContext context = FacesContext.getCurrentInstance();
			context.addMessage(null, message);
		} else {			
			int page = 1;
			while (postCount > 0) {
				pages.add(page);
				++page;
				postCount -= options.getMaxResults();
			}
			goToFirst();
		}
	}
	
	public void goToFirst() {
		goTo(1);
	}

	public void goToPrevious() {
		if (page > 1) {
			goTo(page - 1);
		}
	}	
	
	public void goTo(int page) {
		int firstResult = (page - 1) * options.getMaxResults();
		options.setFirstResult(firstResult);
		AbstractEntityController<Identifier, Entity, EntitySearchOptions> controller = getController();
		result = controller.searchEntity(options);
		this.page = page;
	}
	
	protected abstract AbstractEntityController<Identifier, Entity, EntitySearchOptions> getController();

	
	public void goToNext() {
		if (page < pages.size()) {
			goTo(page + 1);
		}
	}
	
	public void goToLast() {
		goTo(pages.size());
	}		
	
}
